// Copyright 2010, Vanya Davidenko.
// Используемая кодировка: UTF-8.

#ifndef LIBV_MULTI_CLASS_H_
#define LIBV_MULTI_CLASS_H_

#include <loki/Typelist.h>



namespace libv
{

/** Генерация универсального базового класса, который позволяет преобразовывать
  * наследника в любой из типов переданного списка типов и выполнять его методы.
  * В случае, если классу будут переданы базовый класс и его наследник,
  * преобразование к базовому приведет к неоднозначности. В таком случае
  * рекомендуется использовать декорирующую версию — ManglingMultiClass.
  *
  * Класс использует protected-наследование для того, чтобы его явно
  * использовал один наследник, но он не использовался просто в качестве типа.
  * MultiBaseClass нарушает принцип подстановки Лисков — вызов методов через
  * указатели на базовые классы приводит к разным результатам.
  *
  * Пример:
  * @code
  *
  * class Type1
  * {
  *   public:
  *     void Foo() { ... }
  * };
  *
  * class Type2
  * {
  *   public:
  *     void Foo() { ... }
  * };
  *
  *
  * template<class Typelist> class A : private MultiBaseClass<Typelist>
  * {
  *    void ComposedFoo()  // вызов метода Foo для переданных типов
  *    {
  *       typedef typename Typelist::Head FirstType;
  *       typedef typename Typelist::Tail T_;
  *       typedef typename T_::Head SecondType;
  *
  *       this->Mangling<FirstType>::Foo();                 // способ 1
  *       static_cast<Mangling<SecondType>*>(this)->Foo();  // способ 2
  *    }
  * }
  *
  * // Type1 и Type2 не являются базовыми друг для друга.
  * typedef A<LOKI_TYPELIST_2(Type1, Type2)> ComposedA;
  * @endcode */
template<class> class MultiBaseClass;

template<class THead, class TTail>
class MultiBaseClass< Loki::Typelist<THead, TTail> >
    : protected THead,
      protected MultiBaseClass<TTail> {};

template<> class MultiBaseClass<Loki::NullType> {};





/** Декорация имени типа.
  * Mangling<Element> ведет себя точно так же как Element, но имеет другое имя,
  * что позволяет использовать базовый класс и его наследника
  * при множественном наследовании. */
template<class Element> class Mangling : public Element {};


/** Декорирующая версия MultiBaseClass.
  * Хотя класс и использует невиртуальное множественное наследование,
  * но это не приведет к неоднозначности выбора, так как используется
  * декорирование (mangling) имен.
  * @sa MultiBaseClass.
  * @sa Mangling.
  * @code
  *
  * class Base
  * {
  *   public:
  *     void Foo() {}
  * };
  *
  * class Derived : public Base
  * {
  *   public:
  *     void Foo() {}
  * };
  *
  *
  * template<class Typelist> class A : private MultiBaseClass<Typelist>
  * {
  *    void ComposedFoo()  // вызов метода Foo для переданных типов
  *    {
  *       typedef typename Typelist::Head FirstType;
  *       typedef typename Typelist::Tail T_;
  *       typedef typename T_::Head SecondType;
  *
  *       this->Mangling<FirstType>::Foo();                 // способ 1
  *       static_cast<Mangling<SecondType>*>(this)->Foo();  // способ 2
  *    }
  * }
  *
  * // Использование декорирования не приводит к неоднозначности.
  * typedef A<LOKI_TYPELIST_2(Base, Derived)> ComposedA;
  * @endcode */
template<class> class MangledMultiBaseClass;

template<class THead, class TTail>
class MangledMultiBaseClass< Loki::Typelist<THead, TTail> >
    : protected Mangling<THead>,
      protected MangledMultiBaseClass<TTail> {};

template<> class MangledMultiBaseClass<Loki::NullType> {};

}  // libv

#endif  // LIBV_MULTI_CLASS_H_
